package org.fmblzf.library.version;

import android.app.AlertDialog;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Environment;
import android.os.Message;
import android.util.Log;
import android.util.Xml;
import android.widget.Toast;

import org.fmblzf.library.asyc.AsycHandler;
import org.fmblzf.library.asyc.AsycOperate;
import org.fmblzf.library.asyc.Intant;
import org.fmblzf.library.inter.AsmHandleListener;
import org.fmblzf.library.inter.InterListener;
import org.fmblzf.library.util.LogUtils;
import org.xmlpull.v1.XmlPullParser;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;

/**
 * Created by zhaofeng on 2016/1/8.
 * 版本更新类
 */
public class VersionUpdate {

    /**
     * 当前标记
     */
    private static String TAG = VersionUpdate.class.getName();
    /**
     * 静态实体类
     */
    private static VersionUpdate instance;
    /**
     * 上下文实例
     */
    private Context mContext;

    /**
     * 完成后的操作
     */
    private AsmHandleListener mAsmHandleListener;

    /**
     * 进度条
     */
    private ProgressDialog pd = null;

    /**
     * 单例模式，私有构造器
     *
     * @param context
     */
    private VersionUpdate(Context context) {
        this.mContext = context;
    }

    /**
     * 对外公共接口，获取对应的实例
     * 线程安全
     *
     * @param context
     * @return
     */
    public static synchronized VersionUpdate getInstance(Context context) {
        if (instance == null) {
            instance = new VersionUpdate(context);
        }
        return instance;
    }

    /**
     * 初始化版本信息
     *
     * @param versionPath 版本信息文件路径
     */
    public void initAppVersion(String versionPath, AsmHandleListener asmHandleListener) {
        //初始化本地版本信息
        try {
            AppConfig.localVersion = mContext.getPackageManager().getPackageInfo(mContext.getPackageName(), 0).versionCode;
        } catch (PackageManager.NameNotFoundException e) {
            e.printStackTrace();
        }
        //异步初始化服务器端apk版本信息
        this.mAsmHandleListener = asmHandleListener;
        AsycOperate.getInstance(mContext).startAsyOperate(new GetWebVesionInfoAsmHandler(), new GetWebVesionInfo(versionPath));
    }



    /**
     * 检查是否有新版本，有新版本给出提示，是否更新最新版本
     */
    public void checkVersion() {
        if (AppConfig.serviceVersion > AppConfig.localVersion) {
            //有新版本需要更新
            if (LogUtils.isLog)
                Log.i(TAG, "服务器版本号" + AppConfig.serviceVersion + ";本地App版本号" + AppConfig.localVersion);
            showVersionDialog();
        }
    }

    /**
     * 显示版本更新的提示框
     */
    private void showVersionDialog() {
        AlertDialog.Builder builder = new AlertDialog.Builder(mContext);
        builder.setTitle("软件更新");
        builder.setMessage("发现新版本,建议立即更新使用");
        builder.setPositiveButton("更新", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                //开始版本更新
                if (LogUtils.isShowToast)
                    Toast.makeText(mContext, "开始版本更新", Toast.LENGTH_LONG).show();
                dialog.dismiss();
                AsycOperate.getInstance(mContext).startAsyOperate(new AsmHandleListener() {
                    @Override
                    public Object start(int action, Object... objs) {
                        if (action == Intant.START) {
                            if (objs[0] instanceof Message) {
                                Message m = (Message) objs[0];
                                if (pd == null) {
                                    pd = new ProgressDialog(mContext);//设置进度条风格，风格为圆形，旋转的
                                    pd.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
                                    //设置ProgressDialog 标题
                                    pd.setTitle("版本更新");
                                    //设置ProgressDialog 提示信息
//                                    pd.setMessage("长方形进度条");
                                    //设置ProgressDialog 标题图标
                                    pd.setIcon(android.R.drawable.ic_dialog_alert);
                                }
                                pd.setMax(m.arg1);
                                pd.show();
                                pd.setProgress(0);
                            }
                        }
                        return null;
                    }

                    @Override
                    public Object process(int action, Object... objs) {
                        if (action == Intant.PROCESS) {
                            if (objs[0] instanceof Message) {
                                Message m = (Message) objs[0];
                                pd.setProgress(m.arg1);
                            }
                        }
                        return null;
                    }

                    @Override
                    public Object sucess(int action, Object... objs) {
                        File file = null;
                        if (action == Intant.SUCESS) {
                            pd.dismiss();
                            if (objs[0] instanceof Message) {
                                Message m = (Message) objs[0];
                                if (m.obj instanceof File) {
                                    file = (File) m.obj;
                                }
                            }
                        }
                        if (file != null) {
                            installApk(file);
                        }
                        return null;
                    }

                    @Override
                    public Object fail(int action, Object... objs) {
                        pd.dismiss();
                        return null;
                    }
                }, new InterListener() {
                    @Override
                    public Object action(int action, Object... objs) throws Exception {
                        File file = null;
                        try {
//                            String savePath = Environment.getExternalStorageDirectory()+File.separator+"update.apk";
                            AsycHandler handler = null;
                            if (objs != null && objs.length > 0 && objs[0] instanceof AsycHandler) {
                                handler = (AsycHandler) objs[0];
                            }

                            file = getFileFromServer(AppConfig.serviceApkPath, handler);
                            //checkStorage();
//                            file = downloadFile(AppConfig.serviceApkPath,"update.apk");
                            //Toast.makeText(mContext,"文件下载成功",Toast.LENGTH_LONG).show();
                        } catch (Exception e) {

                            Log.e("TAG", e.getMessage());
                        }
                        return file;
                    }
                });
            }
        });
        builder.setNegativeButton("取消", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                dialog.dismiss();
                if (mAsmHandleListener != null) {
                    mAsmHandleListener.sucess(0, new Object[]{null});
                }
            }
        });
        builder.create().show();
    }


    /**
     * 消息接收处理类
     */
    private class GetWebVesionInfoAsmHandler implements AsmHandleListener {
        @Override
        public Object start(int action, Object... objs) {
            return null;
        }

        @Override
        public Object process(int action, Object... objs) {
            return null;
        }

        @Override
        public Object sucess(int action, Object... objs) {
            checkVersion();
            return null;
        }

        @Override
        public Object fail(int action, Object... objs) {
            if (mAsmHandleListener != null) {
                mAsmHandleListener.fail(action, objs);
            }
            return null;
        }
    }
    /**
     * 获取服务器端的apk版本信息
     */
    private class GetWebVesionInfo implements InterListener {
        //服务器路径
        private String path = null;

        public GetWebVesionInfo(String versionPath) {
            this.path = versionPath;
        }

        @Override
        public Object action(int action, Object... objs) throws Exception {
            initServiceAppVersion(path);
            return null;
        }
    }
    /**
     * 初始化apk服务器端的信息
     * 用pull解析器解析服务器返回的xml文件 (xml封装了版本号) 
     * @param path
     * @throws Exception
     */
    public void initServiceAppVersion(String path) throws Exception {
        URL url = new URL(path);
        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
        conn.setConnectTimeout(5000);
        InputStream is = conn.getInputStream();
        XmlPullParser parser = Xml.newPullParser();
        parser.setInput(is, "utf-8");//设置解析的数据源    
        int type = parser.getEventType();
        while (type != XmlPullParser.END_DOCUMENT) {
            switch (type) {
                case XmlPullParser.START_TAG:
                    if ("version".equals(parser.getName())) {
                        AppConfig.serviceVersion = new Integer(parser.nextText()); //获取版本号   
                    } else if ("url".equals(parser.getName())) {
                        AppConfig.serviceApkPath = parser.nextText(); //获取要升级的APK文件   
                    } else if ("description".equals(parser.getName())) {
                        AppConfig.newApkDesc = parser.nextText(); //获取该文件的信息   
                    }
                    break;
            }
            type = parser.next();
        }
    }
    /**
     * 下载apk
     * @param path
     * @return
     * @throws Exception
     */
    public File getFileFromServer(String path, AsycHandler handler) throws Exception {
        //如果相等的话表示当前的sdcard挂载在手机上并且是可用的
        if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
            String savePath = Environment.getExternalStorageDirectory() + "/temp_apk/";
            File f = new File(savePath);
            if (!f.exists()) {
                f.mkdirs();
            }
            File file = new File(savePath + "update.apk");
            if (file.exists()) {
                file.delete();
            }
            file.createNewFile();

            URL url = new URL(path);
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            conn.setConnectTimeout(5000);
            //获取到文件的大小
            if (handler != null) {
                Message max_message = handler.obtainMessage();
                max_message.what = Intant.START;
                max_message.arg1 = conn.getContentLength();
                handler.sendMessage(max_message);
            }
            InputStream is = conn.getInputStream();
            FileOutputStream fos = new FileOutputStream(file);
            BufferedInputStream bis = new BufferedInputStream(is);
            byte[] buffer = new byte[1024];
            int len;
            int total = 0;
            while ((len = bis.read(buffer)) != -1) {
                fos.write(buffer, 0, len);
                total += len;
                //获取当前下载量
                if (handler != null) {
                    Message message = handler.obtainMessage();
                    message.what = Intant.PROCESS;
                    message.arg1 = total;
                    handler.sendMessage(message);
                }
            }
            fos.close();
            bis.close();
            is.close();
            return file;
        }
        return null;
    }
    /**
     * 安装apk
     * @param file
     */
    private void installApk(File file) {
        Intent intent = new Intent();
        //执行动作
        intent.setAction(Intent.ACTION_VIEW);
        //执行的数据类型
        intent.setDataAndType(Uri.fromFile(file), "application/vnd.android.package-archive");
        mContext.startActivity(intent);
    }


    //--以下是无用代码


    private void checkStorage() {
        if (!isExternalStorageAvailable() || isExternalStorageReadOnly()) {
            Toast.makeText(mContext, "不可以读写操作SD卡", Toast.LENGTH_LONG).show();
        } else {
            Toast.makeText(mContext, "可以读写操作SD卡", Toast.LENGTH_LONG).show();
        }

    }

    private static boolean isExternalStorageReadOnly() {
        String extStorageState = Environment.getExternalStorageState();
        if (Environment.MEDIA_MOUNTED_READ_ONLY.equals(extStorageState)) {
            return true;
        }
        return false;
    }

    private static boolean isExternalStorageAvailable() {
        String extStorageState = Environment.getExternalStorageState();
        if (Environment.MEDIA_MOUNTED.equals(extStorageState)) {
            return true;
        }
        return false;
    }
    /**
     * 下载远程文件并保存到本地
     *
     * @param remoteFilePath 远程文件路径
     * @param fileName  本地文件路径
     */
    public File downloadFile(String remoteFilePath, String fileName) throws IOException {
        File f = new File(Environment.getExternalStorageDirectory().getAbsoluteFile(), fileName);
        if (!f.exists()) {
            f.createNewFile();
            Toast.makeText(mContext, "文件创建成功", Toast.LENGTH_LONG).show();
        }
        URL urlfile = null;
        HttpURLConnection httpUrl = null;
        BufferedInputStream bis = null;
        BufferedOutputStream bos = null;
        try {
            urlfile = new URL(remoteFilePath);
            httpUrl = (HttpURLConnection) urlfile.openConnection();
            httpUrl.connect();
            bis = new BufferedInputStream(httpUrl.getInputStream());
            bos = new BufferedOutputStream(new FileOutputStream(f));
            int len = 2048;
            byte[] b = new byte[len];
            while ((len = bis.read(b)) != -1) {
                bos.write(b, 0, len);
            }
            bos.flush();
            bis.close();
            httpUrl.disconnect();

            return f;

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                bis.close();
                bos.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return null;
    }




}
